package org.soft.xinyu.equipmentmanagement.service.impl.user;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.soft.xinyu.equipmentmanagement.config.redis.RedisCache;
import org.soft.xinyu.equipmentmanagement.config.security.SecurityUser;
import org.soft.xinyu.equipmentmanagement.entity.User;
import org.soft.xinyu.equipmentmanagement.entity.dto.LoginDto;
import org.soft.xinyu.equipmentmanagement.entity.dto.RegisterDto;
import org.soft.xinyu.equipmentmanagement.mapper.UserMapper;
import org.soft.xinyu.equipmentmanagement.result.Result;
import org.soft.xinyu.equipmentmanagement.service.user.UserService;
import org.soft.xinyu.equipmentmanagement.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

@Service
public class UserServiceImpl implements UserService, UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtUtil jwtUtils;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder bcryptPasswordEncoder;

    /**
     * 用户登入
     * @param loginDto 账号密码输入
     * @return jwt
     */
    @Override
    public Result userLogin(LoginDto loginDto) {
        if (loginDto == null) {
            return Result.fail("用户名密码为空！");
        }
        if (loginDto.getUserName().isEmpty() && loginDto.getUserEmail().isEmpty()) {
            return Result.fail("用户名为空！");
        }
        UsernamePasswordAuthenticationToken authToken = null;
        if (loginDto.getUserName().isEmpty()){
            authToken = new UsernamePasswordAuthenticationToken(loginDto.getUserEmail(), loginDto.getUserPassword());
        }else {
            authToken = new UsernamePasswordAuthenticationToken(loginDto.getUserName(), loginDto.getUserPassword());
        }
        // 使用authenticationManager调用loadUserByUsername获取数据库中的用户信息,
        Authentication authentication = authenticationManager.authenticate(authToken);
        if(authentication == null) {
            throw new RuntimeException("Login false");
        }

        SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
        Integer useId = securityUser.getUser().getId();
        String usrName = securityUser.getUsername();

        List<String> authList = new ArrayList<String>();
        for (GrantedAuthority auth : securityUser.getAuthorities()) {
            authList.add(auth.getAuthority());
        }
        String jwt = JwtUtil.createJwt("user login", useId);
        // 存入Redis
        redisCache.setCacheObject("login:"+useId,securityUser);
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("token", jwt);
        return Result.success(map);
    }

    /**
     * 用户注册
     * 逻辑很简单, 就是将内容传入
     * @param registerDto
     * @return
     */
    @Override
    @Transactional()
    public Result userRegister(RegisterDto registerDto) {
        // 先查询用户是否存在, 存在就用ResultInfo返回消息即可
        if (userMapper.selectCount(new QueryWrapper<User>().lambda().eq(User::getUserEmail, registerDto.getUserEmail())) > 0){
            return Result.fail( "用户名已存在");
        }
        //创建用户, 设置其中的内容
        User user = new User();
        user.setUserName(registerDto.getUserName());
        user.setUserEmail(registerDto.getUserEmail());
        // 在这里将用户密码进行加密, 存入数据库 (可不能对密码明文存储)
        user.setUserPassword(bcryptPasswordEncoder.encode(registerDto.getUserPassword()));
        user.setUserRole("user");
        user.setEnabled(1); //经过管理员确认后才可使用 TODO:这里需要修改
        user.setAccountNoExpired(1);
        user.setCredentialsNoExpired(1);
        user.setAccountNoLocked(1);
        user.setUserToken("a");

        return Result.success("注册成功！", userMapper.insert(user));
    }


    @Override
    public void userLogout(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        SecurityUser loginUser = (SecurityUser) authentication.getPrincipal();
        int userid = loginUser.getUser().getId();
        redisCache.deleteObject("login:"+userid);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        boolean matches = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE).matcher(username).matches();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.lambda()
                .eq(matches, User::getUserEmail, username)
                .eq(!matches, User::getUserName, username);
        User user = userMapper.selectOne(userQueryWrapper);
        if (user == null) {
            throw new UsernameNotFoundException("username not found");
        }
        // 在这里将用户的权限转换为字符串数组
        List<String> list = new ArrayList<>(Arrays.asList(user.getUserRole()));
        return new SecurityUser(user, list);
    }
}
